package com.server.commons.minio.base;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import com.server.model.all.enums.MimeTypeEnum;
import com.server.common.code.error.BusinessException;
import com.server.commons.file.base.BaseFile;
import com.server.commons.file.interfaces.FileFactoryInterface;
import com.server.commons.file.model.input.UploadFileInput;
import com.server.commons.file.model.output.UploadFileOutput;
import com.server.commons.minio.config.MinioConfig;
import io.minio.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.InputStream;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * minio的框架
 * 文档-https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-policy-language-overview.html
 * @author LXC
 * @date 2022/5/7 16:40
 */
@Slf4j
public abstract class BaseMinioFile extends BaseFile {

    @Resource
    private MinioConfig minioConfig;
    @Resource
    private FileFactoryInterface fileFactoryInterface;

    @Resource
    private MinioClient minioClient;

    //启动时加入到工程中
    @PostConstruct
    public void init() {
        fileFactoryInterface.register(getBucketNameEnum(), this);
    }


    @Override
    public UploadFileOutput uploadFile(UploadFileInput uploadFileInput) {
        UploadFileOutput uploadFileOutput = super.uploadFile(uploadFileInput);

        String bucketName = getBucketNameEnum().getName();

        //获取contentType
        String contentType = MimeTypeEnum.getContentType(uploadFileInput.getSuffix());

        try (InputStream inputStream = IoUtil.toStream(uploadFileInput.getBytes())){
            //创建桶
            makeBucket(bucketName);
            //上传
            PutObjectArgs build = PutObjectArgs.builder()
                    .contentType(contentType)
                    .bucket(bucketName)
                    .object(uploadFileInput.getPath())
                    .stream(inputStream, inputStream.available(), -1)
                    .build();
            minioClient.putObject(build);


            return uploadFileOutput;
        } catch (Exception e) {
            log.error("uploadFile-",e);
        }
        throw new BusinessException("上传文件失败");
    }

    @Override
    public byte[] downFile(String paths) {
        String bucketName = getBucketNameEnum().getName();
        paths = paths.substring(bucketName.length()+1);
        String fileName = UUID.randomUUID().toString();
        try {
            DownloadObjectArgs downloadObjectArgs = DownloadObjectArgs.builder()
                    .bucket(bucketName)
                    .object(paths)
                    .filename(fileName)
                    .build();
            minioClient.downloadObject(downloadObjectArgs);
            //获取文件地址
            return FileUtil.readBytes(fileName);
        } catch (Exception e) {
            log.error("uploadFile-",e);
        }finally {
            FileUtil.del(fileName);
        }
        throw new BusinessException("下载文件失败");
    }

    @Override
    public Boolean deleteFile(String paths) {
        try {
            String bucketName = getBucketNameEnum().getName();
            minioClient.removeObject(RemoveObjectArgs.builder()
                    .bucket(bucketName)
                    .object(paths)
                    .build());
            return true;
        } catch (Exception e) {
            log.error("文件删除失败",e);
        }
        throw new BusinessException("删除文件失败");
    }

    //region 创建桶
    private void makeBucket(String bucketName){
        try {
            boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (found) {
                log.info("bucket已经存在");
                return;
            }
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());

            if(!ObjectUtils.isEmpty(getPolicy())){
                minioClient.setBucketPolicy(SetBucketPolicyArgs.builder()
                        .bucket(bucketName)
                        .config(getPolicy())
                        .build());
            }
            return ;
        }catch (Exception e){
            log.error("创建Bucket失败",e);
        }
        throw new BusinessException("创建Bucket失败");
    }
    //endregion

    /**
     * 获取文件大小
     * @author LXC
     * @date 2022/11/20 18:28
     */
    @Override
    public Long getSize(String bucketName, String paths) {
        try {
            StatObjectResponse statObjectResponse = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(paths).build());
            return statObjectResponse.size();
        } catch (Exception e) {
            log.error("文件获取失败",e);
        }
        throw new BusinessException("获取文件大小失败");
    }

    @Override
    public String getShareUrl(String paths,int duration) {
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                            .bucket(getBucketNameEnum().getName())
                            .method(Method.GET)
                            .object(paths)
                            .expiry(duration,TimeUnit.SECONDS)
                    .build());
        } catch (Exception e) {
            log.error("文件URL获取失败",e);
        }
        throw new BusinessException("文件URL获取失败");
    }
}
